import { Scene } from './Scene';
import { EventEmitter } from '../utils/EventEmitter';

export interface SceneManagerOptions {
    initialScene?: Scene;
}

export class SceneManager extends EventEmitter {
    private scenes: Map<string, Scene>;
    private currentScene: Scene | null;
    private nextScene: Scene | null;
    private _isTransitioning: boolean;
    
    constructor(options: SceneManagerOptions = {}) {
        super();
        
        this.scenes = new Map();
        this.currentScene = null;
        this.nextScene = null;
        this._isTransitioning = false;
        
        // Add initial scene if provided
        if (options.initialScene) {
            this.addScene(options.initialScene);
            this.switchToScene(options.initialScene.name);
        }
    }
    
    /**
     * Add a scene to the manager
     */
    public addScene(scene: Scene): void {
        if (this.scenes.has(scene.name)) {
            throw new Error(`Scene with name ${scene.name} already exists`);
        }
        
        this.scenes.set(scene.name, scene);
        this.emit('sceneAdded', scene);
    }
    
    /**
     * Remove a scene from the manager
     */
    public removeScene(scene: Scene): void {
        if (this.scenes.has(scene.name)) {
            this.scenes.delete(scene.name);
            
            // If this was the current scene, clear it
            if (this.currentScene === scene) {
                this.currentScene = null;
            }
            
            this.emit('sceneRemoved', scene);
        }
    }
    
    /**
     * Get a scene by name
     */
    public getScene(name: string): Scene | null {
        return this.scenes.get(name) || null;
    }
    
    /**
     * Get all scenes
     */
    public getScenes(): Scene[] {
        return Array.from(this.scenes.values());
    }
    
    /**
     * Get the current scene
     */
    public getCurrentScene(): Scene | null {
        return this.currentScene;
    }
    
    /**
     * Switch to a scene by name
     */
    public switchToScene(name: string): void {
        const scene = this.scenes.get(name);
        if (!scene) {
            throw new Error(`Scene ${name} not found`);
        }
        
        if (this.currentScene === scene) {
            return;
        }
        
        this.nextScene = scene;
        this._isTransitioning = true;
        
        // Deactivate current scene if it exists
        if (this.currentScene) {
            this.currentScene.deactivate();
            this.emit('sceneDeactivated', this.currentScene);
        }
        
        // Activate new scene
        scene.activate();
        this.currentScene = scene;
        this.nextScene = null;
        this._isTransitioning = false;
        
        this.emit('sceneSwitched', scene);
    }
    
    /**
     * Check if a scene transition is in progress
     */
    public isTransitioning(): boolean {
        return this._isTransitioning;
    }
    
    /**
     * Update the current scene
     */
    public update(deltaTime: number): void {
        if (this.currentScene) {
            this.currentScene.update(deltaTime);
        }
    }
    
    /**
     * Render the current scene
     */
    public render(ctx: CanvasRenderingContext2D): void {
        if (this.currentScene) {
            this.currentScene.render(ctx);
        }
    }
    
    /**
     * Clear all scenes
     */
    public clear(): void {
        // Deactivate current scene
        if (this.currentScene) {
            this.currentScene.deactivate();
            this.currentScene = null;
        }
        
        // Clear all scenes
        for (const scene of this.scenes.values()) {
            scene.clear();
        }
        
        this.scenes.clear();
        this.nextScene = null;
        this._isTransitioning = false;
        
        this.emit('cleared');
    }
    
    /**
     * Destroy the scene manager and all scenes
     */
    public destroy(): void {
        // Destroy all scenes
        for (const scene of this.scenes.values()) {
            scene.destroy();
        }
        
        this.scenes.clear();
        this.currentScene = null;
        this.nextScene = null;
        this._isTransitioning = false;
        
        this.emit('destroy');
        this.removeAllListeners();
    }
    
    /**
     * Check if a scene exists
     */
    public hasScene(name: string): boolean {
        return this.scenes.has(name);
    }
    
    /**
     * Get the number of scenes
     */
    public getSceneCount(): number {
        return this.scenes.size;
    }
    
    /**
     * Get scene names
     */
    public getSceneNames(): string[] {
        return Array.from(this.scenes.keys());
    }
} 